#ifndef __SEGMENTATION_H__
#define __SEGMENTATION_H__

#include <stdlib.h>
#include "GCoptimization.h"

struct Bounds
{
  int minX;
  int maxX;
  int minY;
  int maxY;
};


class Segmentation {
public:

	typedef double EnergyTermType;
	typedef short LabelID;
	typedef short ImageType;
	Segmentation(int height, int width, int depth, int numberOfImagesValue, int numberOfRegions, LabelID* initialPoints, ImageType* images);
	~Segmentation();

	inline int getHeight(){return height;};
	inline int getWidth(){return width;};
	inline int getDepth(){return depth;};

	inline int getNumberOfImages(){return numberOfImages;};
	inline int getNumberOfRegions(){return numberOfRegions;};

	void setMask(LabelID* newMask);
	inline LabelID* getMask(){return mask;};
	int insideBounds(int x, int y);

	void setInitialPoints(LabelID* newInitialPoints);
	void exportInitialPoints(LabelID* points);

	inline int getPrintFlag(){return printFlag;};
	inline void setPrintFlag(int value){printFlag = value;};

	inline int getIterations(){return iterations;};
	inline void setIterations(int value){iterations = value;};

	inline double getSliceDistance(){return sliceDistance;};
	inline void setSliceDistance(double distance){sliceDistance = distance;};

	void setSmoothFactor(double factor);

	void exportMean(int region, double* exportMean);
	void exportVariance(int region, double* exportVar);
	void exportCovariance(int region, double* exportCov);
	void getCurtosis(int region, double* results);

	void exportDataCost(double* pythonDataCost);

	void expandRegions(int iterations);
	void expansion(int iterations);
private:

	int height;
	int width;
	int depth;
	int numberOfImages;
	int numberOfRegions;

	LabelID* initialPoints;
	ImageType* images;

	int printFlag;
	int iterations;
	LabelID* mask;

	double sliceDistance;
	double* smoothnessCost;

	double* mean;
	double* variance;
	double* covariance;

	double* dataCost;

	void calculateMeanAndCovariance();
	void calculateDataCost();
	Bounds bounds;
	GCoptimizationGeneralGraph* graph;

	void setBounds(int minX, int maxX, int minY, int maxY);
	int setNeighboursInSlide(int x, int y, int zFrom, int zTo);
	void setFullNeighbours();
	int isConnected(int x, int y, int z);
	void initGraph();
	void updateInitialPoints(LabelID* points);
};

#endif
